import { _decorator } from 'cc';
import { GridNode } from '../Scripts/GridNode';

export class AStarPath {
    // 直线移动代价
    private static readonly STRAIGHT_COST: number = 10;
    // 斜线移动代价
    private static readonly DIAGONAL_COST: number = 14;

    // 开启列表和关闭列表
    private _openList: GridNode[] = [];
    private _closeList: GridNode[] = [];

    // 寻找从起点到终点的路径
    public findPath(startNode: GridNode, endNode: GridNode, grid: GridNode[][]): GridNode[] {
        // 首先检查起点和终点是否可通行
        if (!startNode.walkable || !endNode.walkable) {
            return null;
        }

        // 重置数据
        this._openList = [];
        this._closeList = [];
        startNode.reset();
        
        // 将起点加入开启列表
        this._openList.push(startNode);

        // 持续检查直到找到路径或确定无路可走
        while (this._openList.length > 0) {
            // 获取f值最小的节点
            const currentNode = this._getMinFNodeFromOpen();
            
            // 如果是终点，返回路径
            if (currentNode === endNode) {
                return this._tracePath(endNode);
            }

            // 将当前节点移到关闭列表
            this._removeFromOpenList(currentNode);
            this._closeList.push(currentNode);

            // 检查周围的节点
            const neighbors = this._getNeighbors(currentNode, grid);
            for (const neighbor of neighbors) {
                // 跳过不可通行或已在关闭列表中的节点
                if (!neighbor.walkable || this._isInCloseList(neighbor)) {
                    continue;
                }

                // 计算新的g值（如果是斜向移动，代价更高）
                const newG = currentNode.g + this._getDistance(currentNode, neighbor);

                // 如果是新节点或找到更好的路径
                if (!this._isInOpenList(neighbor) || newG < neighbor.g) {
                    neighbor.g = newG;
                    neighbor.h = neighbor.manhattanDistance(endNode) * AStarPath.STRAIGHT_COST;
                    neighbor.parent = currentNode;

                    if (!this._isInOpenList(neighbor)) {
                        this._openList.push(neighbor);
                    }
                }
            }
        }

        // 没有找到路径
        return null;
    }

    // 检查节点是否在开启列表中
    private _isInOpenList(node: GridNode): boolean {
        return this._openList.indexOf(node) !== -1;
    }

    // 检查节点是否在关闭列表中
    private _isInCloseList(node: GridNode): boolean {
        return this._closeList.indexOf(node) !== -1;
    }

    // 从开启列表中获取f值最小的节点
    private _getMinFNodeFromOpen(): GridNode {
        let minNode = this._openList[0];
        for (const node of this._openList) {
            if (node.f < minNode.f) {
                minNode = node;
            }
        }
        return minNode;
    }

    // 从开启列表中移除节点
    private _removeFromOpenList(node: GridNode): void {
        const index = this._openList.indexOf(node);
        if (index !== -1) {
            this._openList.splice(index, 1);
        }
    }

    // 获取相邻节点（包括斜向移动检查）
    private _getNeighbors(node: GridNode, grid: GridNode[][]): GridNode[] {
        const neighbors: GridNode[] = [];
        const rowCount = grid.length;
        const colCount = grid[0].length;

        // 检查八个方向
        for (let dx = -1; dx <= 1; dx++) {
            for (let dy = -1; dy <= 1; dy++) {
                if (dx === 0 && dy === 0) continue;

                const newX = node.x + dx;
                const newY = node.y + dy;

                // 检查是否在地图范围内
                if (newX >= 0 && newX < colCount && newY >= 0 && newY < rowCount) {
                    // 检查斜向移动时的两个相邻格子是否都可通行
                    if (Math.abs(dx) === 1 && Math.abs(dy) === 1) {
                        // 如果是斜向移动，需要检查两个相邻的格子是否可通行
                        if (!grid[node.y][newX].walkable || !grid[newY][node.x].walkable) {
                            continue; // 如果任一相邻格子不可通行，则不允许斜向移动
                        }
                    }
                    neighbors.push(grid[newY][newX]);
                }
            }
        }

        return neighbors;
    }

    // 计算两个相邻节点之间的距离
    private _getDistance(nodeA: GridNode, nodeB: GridNode): number {
        const dx = Math.abs(nodeA.x - nodeB.x);
        const dy = Math.abs(nodeA.y - nodeB.y);

        // 如果是斜向移动
        if (dx === 1 && dy === 1) {
            return AStarPath.DIAGONAL_COST;
        }
        return AStarPath.STRAIGHT_COST;
    }

    // 回溯路径
    private _tracePath(endNode: GridNode): GridNode[] {
        const path: GridNode[] = [];
        let currentNode = endNode;

        while (currentNode) {
            path.unshift(currentNode);
            currentNode = currentNode.parent;
        }

        // 不再调用smoothPath，直接返回完整路径
        return path;
    }
}